﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Sgr.SystemInfo.ViewModels;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Sgr.Apis
{
    /// <summary>
    /// 系统信息API扩展
    /// </summary>
    public static class SystemInfoEndpoints
    {
        private static readonly string[] s_healthyStatuses = new[] { "healthy", "degraded", "unhealthy" };

        /// <summary>
        /// 添加系统信息API端点
        /// </summary>
        public static RouteGroupBuilder MapSystemInfoEndpoints(this RouteGroupBuilder group)
        {
            // 为整个组添加认证要求和速率限制
            group.RequireAuthorization();
            group.RequireRateLimiting("limiter-fixed-default");

            group.MapGet("/basic", (IHostEnvironment env, IConfiguration configuration) =>
            {
                string appName = configuration.GetValue<string>("Sgr:AppName") ?? "SGR";

                var process = Process.GetCurrentProcess();

                // 防御性获取程序集：EntryAssembly 可能在某些宿主环境下为 null
                var entryAssembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();

                // 安全获取运行时长（避免在容器或受限环境中抛异常）
                TimeSpan uptime;
                try
                {
                    var startTime = process.StartTime;
                    // 假设 EnsureUtc 是你自定义的扩展方法；若未实现，请替换为标准转换逻辑
                    var utcStartTime = startTime.Kind switch
                    {
                        DateTimeKind.Utc => startTime,
                        DateTimeKind.Local => startTime.ToUniversalTime(),
                        _ => startTime.ToUniversalTime() // Unspecified 视为本地时间转 UTC
                    };
                    uptime = DateTime.UtcNow - utcStartTime;
                }
                catch
                {
                    // 若无法获取启动时间，标记为未知（可用负值或特殊字符串表示，此处用 Zero）
                    uptime = TimeSpan.Zero;
                }

                var status = CheckSystemHealth();
                var containerEnv = DetectContainerEnvironment();

                var baseInfo = new SystemBaseInfo
                {
                    Name = appName,
                    Version = SystemBaseInfo.FormatVersion(entryAssembly.GetName().Version?.ToString() ?? "1.0.0"),
                    Environment = SystemBaseInfo.FormatEnvironment(env.EnvironmentName),
                    Status = status,
                    Uptime = SystemBaseInfo.FormatUptime(uptime),
                    Architecture = RuntimeInformation.ProcessArchitecture.ToString(),
                    ProcessorCount = Environment.ProcessorCount,
                    ContainerEnvironment = containerEnv
                };

                return Results.Ok(baseInfo);
            })
            .WithName("GetSystemBasicInfo")
            .WithSummary("获取系统基础信息")
            .WithDescription("返回应用名称、版本、运行环境、健康状态、运行时长、CPU架构、处理器数量及容器环境等系统基础信息。" +
                             "健康状态基于进程工作集内存占用估算，仅供参考；生产环境建议集成 ASP.NET Core Health Checks。")
            .Produces<SystemBaseInfo>(StatusCodes.Status200OK);

            return group;
        }

        /// <summary>
        /// 检查系统健康状态（简易内存使用率评估）
        /// 注意：此逻辑仅为示例，实际生产应使用 ASP.NET Core Health Checks 机制。
        /// </summary>
        /// <returns>系统健康状态描述 ("healthy", "degraded", "unhealthy")</returns>
        private static string CheckSystemHealth()
        {
            try
            {
                var process = Process.GetCurrentProcess();
                var memoryInfo = GC.GetGCMemoryInfo();

                // 注意：WorkingSet64 包含共享内存，TotalAvailableMemoryBytes 是 GC 可用内存，
                // 此计算仅作粗略参考，不反映真实系统压力。
                if (memoryInfo.TotalAvailableMemoryBytes > 0)
                {
                    double memoryUsagePercent = (double)process.WorkingSet64 / memoryInfo.TotalAvailableMemoryBytes * 100;

                    if (memoryUsagePercent > 90)
                        return s_healthyStatuses[2]; // unhealthy
                    if (memoryUsagePercent > 75)
                        return s_healthyStatuses[1]; // degraded
                }

                return s_healthyStatuses[0]; // healthy
            }
            catch
            {
                // 健康检查失败时返回降级状态，避免因监控逻辑导致 API 不可用
                return s_healthyStatuses[1]; // degraded
            }
        }

        /// <summary>
        /// 检测容器运行环境
        /// </summary>
        /// <returns>容器环境标识："kubernetes", "docker", "other", "non-container"</returns>
        private static string DetectContainerEnvironment()
        {
            try
            {
                // 检查 Kubernetes 环境变量
                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST")))
                {
                    return "kubernetes";
                }

                // 检查 .NET 容器运行时标志（.NET 5+ 设置）
                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER")))
                {
                    return "docker";
                }

                // 在 Linux 中检查 cgroup 路径
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    const string cgroupPath = "/proc/1/cgroup";
                    if (File.Exists(cgroupPath))
                    {
                        var cgroupContent = File.ReadAllText(cgroupPath);

                        if (cgroupContent.Contains("/kubepods/"))
                            return "kubernetes";

                        if (cgroupContent.Contains("/docker/"))
                            return "docker";

                        if (cgroupContent.Contains("/lxc/") || cgroupContent.Contains("/containerd/"))
                            return "other";
                    }
                }

                return "non-container";
            }
            catch
            {
                // 检测失败时默认为非容器环境
                return "non-container";
            }
        }
    }
}